package tcp

import (
	"context"
	"godis/interface/tcp"
	"godis/lib/logger"
	"net"
	"os"
	"os/signal"
	"sync"
	"syscall"
)

type Config struct {
	Address string
}

func ListenAndServeWithSignal(cfg *Config,
	handler tcp.Handler) error { // 监听然后服务使用信号

	closeChan := make(chan struct{})
	sigChan := make(chan os.Signal)
	signal.Notify(sigChan, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
	go func() {
		sig := <-sigChan
		switch sig {
		case syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
			closeChan <- struct{}{}
		}
	}()
	listener, err := net.Listen("tcp", cfg.Address)
	if err != nil {
		return err
	}
	logger.Info("start listen")
	ListenAndServe(listener, handler, closeChan)
	return nil
}

func ListenAndServe(listener net.Listener,
	handler tcp.Handler, closeChan <-chan struct{}) {
	go func() { // 收到信号的时候，保证关闭listener和handler
		<-closeChan
		logger.Info("shutting down")
		_ = listener.Close()
		_ = handler.Close()
	}()
	defer func() { // 保证listener和handler在退出的时候关闭
		_ = listener.Close()
		_ = handler.Close()
	}()
	ctx := context.Background()
	var waitDone sync.WaitGroup

	for true {
		conn, err := listener.Accept()
		if err != nil { // 接收新连接出现了问题，那么跳出死循环
			break
		}
		logger.Info("accepted link")
		waitDone.Add(1) // 每服务一个连接，会+1
		go func() {
			defer func() { // 服务完毕一个连接会-1，这里使用defer是为了避免Handle抛出panic使得Done无法执行
				waitDone.Done()
			}()
			handler.Handle(ctx, conn)
		}()
	}
	waitDone.Wait() // 如果有某协程异常退出，这里会在for外面等待所有的服务都正常退出
}
